﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.ComponentModel;
using System.IO;
using Microsoft.Win32;
using MTS;

namespace MinecraftTopographicalSurvey
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Main main;

        BackgroundWorker renderWorker;

        DateTime startTime;

        private String saveDir;

        public enum Worlds { WORLD1, WORLD2, WORLD3, WORLD4, WORLD5 }

        private class RenderSettings
        {
            private TileImage.TileType _tileType;
            private Worlds _world;

            public TileImage.TileType tileType
            {
                get
                {
                    return this._tileType;
                }
                set
                {
                    this._tileType = value;
                }
            }

            public Worlds world
            {
                get
                {
                    return this._world;
                }
                set
                {
                    this._world = value;
                }
            }
        }

        public MainWindow()
        {
            InitializeComponent();
            saveDir = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), ".minecraft\\saves");
            
            main = new Main();
            if (isWorldAvailable(Worlds.WORLD1))
            {
                this.radioWorld1.IsEnabled = true;
            }
            if (isWorldAvailable(Worlds.WORLD2))
            {
                this.radioWorld2.IsEnabled = true;
            }
            if (isWorldAvailable(Worlds.WORLD3))
            {
                this.radioWorld3.IsEnabled = true;
            }
            if (isWorldAvailable(Worlds.WORLD4))
            {
                this.radioWorld4.IsEnabled = true;
            }
            if (isWorldAvailable(Worlds.WORLD5))
            {
                this.radioWorld5.IsEnabled = true;
            }
            renderWorker = new BackgroundWorker();
            renderWorker.WorkerSupportsCancellation = false;
            renderWorker.WorkerReportsProgress = true;
            renderWorker.DoWork += new DoWorkEventHandler(renderWorker_DoWork);
            renderWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(renderWorker_RunWorkerCompleted);
            renderWorker.ProgressChanged += new ProgressChangedEventHandler(renderWorker_ProgressChanged);
        }

        public Boolean isWorldAvailable(Worlds current)
        {
            Worlds comparator = 0;
            foreach (String worldDir in Directory.GetDirectories(saveDir))
            {
                if (worldDir.EndsWith("World1"))
                {
                    comparator = Worlds.WORLD1;
                }
                else if (worldDir.EndsWith("World2"))
                {
                    comparator = Worlds.WORLD2;
                }
                else if (worldDir.EndsWith("World3"))
                {
                    comparator = Worlds.WORLD3;
                }
                else if (worldDir.EndsWith("World4"))
                {
                    comparator = Worlds.WORLD4;
                }
                else if (worldDir.EndsWith("World5"))
                {
                    comparator = Worlds.WORLD5;
                }
                else
                {
                    return false;
                }
                if (current.Equals(comparator))
                {
                    return true;
                }
            }
            return false;
        }

        public String getWorldPath(Worlds world)
        {
            if (world.Equals(Worlds.WORLD1))
            {
                return Path.Combine(this.saveDir, "World1");
            }
            else if (world.Equals(Worlds.WORLD2))
            {
                return Path.Combine(this.saveDir, "World2");
            }
            else if (world.Equals(Worlds.WORLD3))
            {
                return Path.Combine(this.saveDir, "World3");
            }
            else if (world.Equals(Worlds.WORLD4))
            {
                return Path.Combine(this.saveDir, "World4");
            }
            else if (world.Equals(Worlds.WORLD5))
            {
                return Path.Combine(this.saveDir, "World5");
            }
            else
            {
                return null;
            }
        }

        private void radioWorld1_Click(object sender, RoutedEventArgs e)
        {
            this.startTime = DateTime.Now;
            RenderSettings settings = new RenderSettings();
            if (this.checkTerrain.IsChecked)
            {
                settings.tileType = TileImage.TileType.TERRAIN;
            }
            else if (this.checkOblique.IsChecked)
            {
                settings.tileType = TileImage.TileType.OBLIQUE;
            }
            settings.world = Worlds.WORLD1;
            this.disableMenu();
            renderWorker.RunWorkerAsync(settings);
        }

        private void radioWorld2_Click(object sender, RoutedEventArgs e)
        {
            this.startTime = DateTime.Now;
            RenderSettings settings = new RenderSettings();
            if (this.checkTerrain.IsChecked)
            {
                settings.tileType = TileImage.TileType.TERRAIN;
            }
            else if (this.checkOblique.IsChecked)
            {
                settings.tileType = TileImage.TileType.OBLIQUE;
            }
            settings.world = Worlds.WORLD2;
            this.disableMenu();
            renderWorker.RunWorkerAsync(settings);
            
        }

        private void radioWorld3_Click(object sender, RoutedEventArgs e)
        {
            this.startTime = DateTime.Now;
            RenderSettings settings = new RenderSettings();
            if (this.checkTerrain.IsChecked)
            {
                settings.tileType = TileImage.TileType.TERRAIN;
            }
            else if (this.checkOblique.IsChecked)
            {
                settings.tileType = TileImage.TileType.OBLIQUE;
            }
            settings.world = Worlds.WORLD3;
            this.disableMenu();
            renderWorker.RunWorkerAsync(settings);
        }

        private void radioWorld4_Click(object sender, RoutedEventArgs e)
        {
            this.startTime = DateTime.Now;
            RenderSettings settings = new RenderSettings();
            if (this.checkTerrain.IsChecked)
            {
                settings.tileType = TileImage.TileType.TERRAIN;
            }
            else if (this.checkOblique.IsChecked)
            {
                settings.tileType = TileImage.TileType.OBLIQUE;
            }
            settings.world = Worlds.WORLD4;
            this.disableMenu();
            renderWorker.RunWorkerAsync(settings);
        }

        private void radioWorld5_Click(object sender, RoutedEventArgs e)
        {
            this.startTime = DateTime.Now;
            RenderSettings settings = new RenderSettings();
            if (this.checkTerrain.IsChecked)
            {
                settings.tileType = TileImage.TileType.TERRAIN;
            }
            else if (this.checkOblique.IsChecked)
            {
                settings.tileType = TileImage.TileType.OBLIQUE;
            }
            settings.world = Worlds.WORLD5;
            this.disableMenu();
            renderWorker.RunWorkerAsync(settings);
        }

        private void disableMenu()
        {
            this.RenderMenu.IsEnabled = false;
            this.OptionsMenu.IsEnabled = false;
        }

        private void renderWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            this.startTime = DateTime.Now;
            BackgroundWorker worker = sender as BackgroundWorker;

            RenderSettings settings = (RenderSettings)e.Argument;
            if (settings.tileType.Equals(TileImage.TileType.TERRAIN))
            {
                e.Result = main.renderWorldTerrain(this.getWorldPath(settings.world), worker);
            }
            else if (settings.tileType.Equals(TileImage.TileType.OBLIQUE))
            {
                e.Result = main.renderWorldOblique(this.getWorldPath(settings.world), worker);
            }
        }

        private void renderWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            this.RenderMenu.IsEnabled = true;
            this.OptionsMenu.IsEnabled = true;
            if (e.Error != null)
            {
                MessageBox.Show(e.Error.Message);
            }
            else if (e.Cancelled)
            {
                MessageBox.Show("Aborted!");
            }
            else
            {
                BitmapSource output = (BitmapSource)e.Result;

                TimeSpan elapsed = DateTime.Now - startTime;
                this.updateImage(output);
                this.writeImage(output);
                MessageBox.Show(String.Format("Completed in {0:00}:{1:00}", Math.Floor(elapsed.TotalMinutes), elapsed.Seconds));
            }
        }

        private void renderWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            this.progressBar1.Value = e.ProgressPercentage;
        }

        private void updateImage(BitmapSource image)
        {
            this.imageTerrain.Width = image.Width;
            this.imageTerrain.Height = image.Height;
            this.imageTerrain.Source = image;
        }

        private void writeImage(BitmapSource image)
        {
            
            SaveFileDialog saveDialog = new SaveFileDialog();
            saveDialog.Filter = "png files (*.png)|*.png";
            saveDialog.FilterIndex = 2;
            saveDialog.RestoreDirectory = true;

            if (saveDialog.ShowDialog() == true)
            {
                FileStream stream = new FileStream(saveDialog.FileName, FileMode.Create);
                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(image));
                encoder.Save(stream);
                stream.Close();
                Console.Out.WriteLine("File written to {0}", stream.Name);
            }
        }

        private Point terrainScrollStartPoint;
        private Point terrainScrollStartOffset;

        

        private void scrollTerrain_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            if (this.scrollTerrain.IsMouseOver)
            {
                terrainScrollStartPoint = e.GetPosition(this);
                terrainScrollStartOffset.X = scrollTerrain.HorizontalOffset;
                terrainScrollStartOffset.Y = scrollTerrain.VerticalOffset;

                this.Cursor = (scrollTerrain.ExtentWidth > scrollTerrain.ViewportWidth) ||
                                (scrollTerrain.ExtentHeight > scrollTerrain.ViewportHeight) ?
                                Cursors.ScrollAll : Cursors.Arrow;
            }
            base.OnPreviewMouseDown(e);
        }

        private void scrollTerrain_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                Point point = e.GetPosition(this);

                Point delta = new Point(
                    (point.X > this.terrainScrollStartPoint.X) ?
                        -(point.X - this.terrainScrollStartPoint.X) :
                        (this.terrainScrollStartPoint.X - point.X),

                    (point.Y > this.terrainScrollStartPoint.Y) ?
                        -(point.Y - this.terrainScrollStartPoint.Y) :
                        (this.terrainScrollStartPoint.Y - point.Y));

                scrollTerrain.ScrollToHorizontalOffset(this.terrainScrollStartOffset.X + delta.X);
                scrollTerrain.ScrollToVerticalOffset(this.terrainScrollStartOffset.Y + delta.Y);
            }
            else
            {
                this.Cursor = Cursors.Arrow;
            }
            if (!this.IsMouseOver)
            {
                this.Cursor = Cursors.Arrow;
            }
            base.OnPreviewMouseMove(e);
        }

        private void scrollTerrain_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            this.Cursor = Cursors.Arrow;
            base.OnPreviewMouseUp(e);
        }

    }
}
